/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package utn.tsb.tej.world_logic;

import utn.tsb.tej.comunications.server.RoomGame;
import csm.uttils.Archive;
import csm.uttils.generics.Roster;

/**
 *
 * @author Gaston M. Quiroga <gaston.mauricio.quiroga@gmail.com>
 */
public abstract class WorldLogicFacade {

    public static World world;

    /**
     *This method creates a world object, based in the atributes of the
     * romgame object. It asigns countries and objectives to each player and
     * creates the first round. The next method to call should be getNextPlayer.
     */
    public static void newGame() {// Inicializa todo el world, y distribuye los paises, objetivos entre los jugadores y setea las posibles situaciones.
        Roster<Player> players = new Roster<Player>();
        Roster<Continent> continents = new Roster<Continent>();
        Roster<ObjectiveCard> objectivecards = new Roster<ObjectiveCard>();
        Roster<Situation> situatations = new Roster<Situation>();
        reviewPlayersColors(players);
        world = new World(players, continents, situatations, objectivecards);
        world.newGame();
    }
     public static void newGame(World world, Roster<Player> players) {
        Roster<Continent> continents =world.getContinents();
        Roster<ObjectiveCard> objectivecards =world.getObjectives();
        Roster<Situation> situatations = world.getSituations();
        reviewPlayersColors(players);
        WorldLogicFacade.world = new World(players, continents, situatations, objectivecards);
        WorldLogicFacade.world.newGame();
        System.out.println("Game Created");
    }

    /**
     * Returns the next player in the last round. If the round has ended will
     * return null till the newRound method is called
     * @return
     */
    public static Player getNextPlayer() {// Devuelve el jugador correspondiente al sigueinte turno, y null, si la ronda ya terminó.
        return world.getRounds().getLast().getNextPlayer();
    }

    /**
     * calls newRound(boolena reorder) with the reorder parameter=true;
     * @return true if the new round is created
     */
    public static boolean newRound() {// Pasa a la siguiente ronda del juego. Devuelve true si la transición se logró, y false, si no se cambió la ronda. SOBRECARGA{// Por defecto recibe el valor True, si le paso false por parámetros no cambia el orden de los jugadores.
        return newRound(true,true);
    }

    /**
     *creates a new round if the last is endeded.
     * @param reoarder true if the reorder of the players is needed
     * @return
     */
    public static boolean newRound(boolean reoarder,boolean drawSituation) {
        boolean out = false;
        if (world.getRounds().getLast().isEnded()) {
            world.nextRound(reoarder,drawSituation);
            out = true;
        }
        System.out.println("Nueva Ronda Rodeonda!");
        return out;
    }

    /**
     * adds one armie to the specified country
     * @param country
     * @return false if the country is blocked
     */
    public static boolean addArmie(Country country) {// agrega ejercitos al pais pasado por parámetros, por defecto agrega uno solo, puedo agregar mas de uno por parámetros.
        return addArmies(country, 1);
    }

    /**
     * adds the amount of armies to the specified country
     * @param country
     * @param amount
     * @return false if the country is blocked
     */
    public static boolean addArmies(Country country, int amnt) {

        return country.addArmie(amnt);

    }

    /**
     * substracts one armie to the specified country
     * @param country
     * @param amount
     */
    public void subArmie(Country country) {
        subArmies(country, 1);
    }

    /**
     * Substract the amount of armies from the specifie country
     * @param country
     */
    public static void subArmies(Country country, int amnt) {
        country.subArmy(amnt);
    }

    /**
     * This method put together a roster of the attackable countries from the
     * attacker passed by parameter.
     * @param country
     * @return
     */
    public static Roster<Country> getAttackableCountries(Country country) {// Devuelve los paices atacables por el pais pasado por parámetro.
        return country.getAttackableCountries();
    }

    /**
     * This method creates and validates an attack. If the attack is not valid
     * throws an exception. If the attack is valid, it resolves and alters the
     * world in the right way (altering the number of armies in the countries
     * involved and, if the attack is successful, transfers the defender country
     * the the offensive player.
     * @param from attacker
     * @param to defender
     * @param amnt armies attacking
     * @return attack object resolved
     * @throws Exception if the attack is not valid
     */
    public static Attack attack(Country from, Country to, int amnt) throws Exception {// devuelve un attack con los resultados del ataque.
        Attack attack = new Attack(from, to, amnt);
//        if (!attack.isValid()) {
//            throw new Exception("The attack is not valid");
//        }
        attack.isValid();
        attack.resolve();
        from.setArmies(attack.getAttackerCountryArmiesRemain());
        to.setArmies(attack.getDefenderCountryArmiesRemain());
        if (attack.isConquered()) {
            from.subArmy(1);
            to.addArmie(1);
            world.transferCountry(from.getOwner(), to);
        }
        return attack;
    }

    /**
     *
     * @param from the armies
     * @param to
     * @param amount of armies to move (must be < 4)
     * @return true if the move is valid
     */
    public static boolean moveArmies(Country from, Country to, int amount) {
        boolean out = false;
        if ((from.isLandBordering(to) || from.isSeaBordering(to)) && amount < 4 && from.getArmies() > amount && from.getOwner() == to.getOwner()) {
            for (int i = 0; i < amount; i++) {
                from.subArmy(1);
                to.addArmie(1);
            }
            out = true;
        }
        return out;
    }

    /**
     * If the player have conquered a country this turn he recive a caountry
     * card. If, at this point, the player has a country and its country card
     * and, if the card has not been rewarded in this way, the country will
     * recieve 3 armies.
     * @param player
     */
    public static void getCards(Player player) {// controla si le corresponde al player recibir una tarjeta (de pais o continente), y revise si con los cambios en los paises q hubo en el turno, corresponde agregar ejercitos a alguno de los paises del jugador.  Devuelve una Roster de Tarjetas (por si recibe tarjeta de pais y de continente). NOTA{// agregar a la clase card, un atributo para saber si ya se le cambiaron los ejercitos.
        Card card;
        if (player.isConquered()) {
            card=world.drawCowntryCard();
            player.getCards().addInOrder(card);
        }
        for (int i = 0; i < player.getCards().count(); i++) {
            card = player.getCards().getElementInPosition(i);
            if (card instanceof Country) {
                Country countryCard = (Country) card;
                if (!card.isAwardRecived() && player.getCountries().indexOf(countryCard) != -1) {
                    countryCard.addArmie(3);
                    card.setAwardRecived(true);
                }
            }
        }
        Card continentCard;
        for (int i = 0; i < world.getContinents().count(); i++) {
            if (player.isOwnerOfContinent(world.getContinents().getElementInPosition(i))) {
                continentCard = world.drawContinentCard(world.getContinents().getElementInPosition(i));
                if (continentCard != null) {
                    player.getCards().addInOrder(continentCard);
                }
            }
        }
    }

    /**
     * Checks if any player reachtheir goals. If so, it returns it
     * @return
     */
    public static Player objectivesAccomplished() {// Si algun jugador complió con los objetivos de su tarjeta, o el objetivo común, devuelve el player ganador. NOTA{// Agregar un método isAccomplished() en la clase objective.
        Player player = null;
        Roster<Player> players = world.getRounds().getLast().getTurns();
        for (int i = 0; i < players.count(); i++) {
            if (players.getElementInPosition(i).objectivesAccomplished() || players.getElementInPosition(i).getCountries().count() == 30) {
                player = players.getElementInPosition(i);
            }
        }
        return player;
    }

    /**
     * Returns the amount of armies for a player to add in relation to the
     * amount of his countris and the continents rewards.
     * @param player
     * @return
     */
    public static int getArmiesToAdd(Player player) {// devuelve la cantidad de ejercitos que el jugador puede agregar.
        int armies = (player.getCountries().count() / 2);
        Roster<Continent> continents = world.getContinents();
        for (int i = 0; i < continents.count(); i++) {
            if (player.isOwnerOfContinent(continents.getElementInPosition(i))) {
                armies += continents.getElementInPosition(i).getArmiesReward();
            }
        }

        return armies;
    }

    /**
     * If the exchage is valid, removes the cards from the player and retunrns
     * the amount of armies for a payer to add
     * @param player
     * @param cards
     */
    public static int exchangeCards(Player player, Roster<Card> cards) throws Exception {// Cambia las cartas del jugador al q pertenecen por la cantidad de ejercitos correspondientes y devuelve el nro de ejercitos.
        int armies = 0;
        if (world.isValidExchange(cards)) {
            int changes = player.getChanges() + 1;
            player.setChanges(changes);
            armies = changes * 5;
            if (changes == 1) {
                armies++;
            }
            for (int i = 0; i < cards.count(); i++) {
                player.getCards().remove(cards.getElementInPosition(i));
            }
        }
        return armies;
    }

    /**
     * If the country has more than 6 armies, exchanges 6 armies for one missile.
     * @param country
     * @throws Exception if the country has less than 7 armies
     */
    public static void addMissile(Country country) throws Exception {// hace la transacción de ejercitos por misil, al pais especificado.
        if (country.getArmies() < 7) {
            throw new Exception("Not enough armies!");
        }
        subArmies(country, 6);
        country.setMissile(country.getMissile() + 1);
    }

    /**
     * if necessary, this method remaps colors to players so that two of them
     * do not have the same color
     * @param players
     */
    private static void reviewPlayersColors(Roster<Player> players) {
        Roster<Color> availableColors = new Roster<Color>();
        Roster<Player> aux = new Roster<Player>();
        availableColors.addInOrder(new Color(Color.BLACK));
        availableColors.addInOrder(new Color(Color.BLUE));
        availableColors.addInOrder(new Color(Color.GREEN));
        availableColors.addInOrder(new Color(Color.RED));
        availableColors.addInOrder(new Color(Color.WHITE));
        availableColors.addInOrder(new Color(Color.YELLOW));
        for (int i = 0; i < players.count(); i++) {
            if (null == availableColors.remove(players.getElementInPosition(i).getColor())) {
                aux.addLast(players.remove(players.getElementInPosition(i)));
            }
        }
        int auxcount = aux.count();
        for (int i = 0; i < auxcount; i++) {
            aux.getLast().setColor(availableColors.removeLast());
            players.addLast(aux.removeLast());
        }

    }

    public static Country getCountryByColor(String codeRGB) {
        Roster<Country> countries = world.getCountriesFromContinents(world.getContinents());
        Country country = null;
        for (int i = 0; i < countries.count(); i++) {
            if (countries.getElementInPosition(i).getColor().getCodeRGB().compareToIgnoreCase(codeRGB) == 0) {
                country = countries.getElementInPosition(i);
                break;
            }
        }
        return country;
    }

    public static Player getPlayerByColor(String codeRGB) {
        Player player = null;
        Roster<Player> players = world.getRounds().getLast().getTurns();
        for (int i = 0; i < players.count(); i++) {
            if (players.getElementInPosition(i).getColor().getCodeRGB().compareToIgnoreCase(codeRGB) == 0) {
                player = players.getElementInPosition(i);
                break;
            }
        }
        return player;
    }

    /**
     * Returns the players that are in "Crisis" (they cant get county cards:( )
     * @return null if the situation is not crisys.
     */
    public static Roster<Player> getCrisisRolls() {
        Roster<Player> players = null;
        if (world.getRounds().getLast().getSituation() instanceof SituationCrisis) {
            players = ((SituationCrisis) world.getRounds().getLast().getSituation()).getCrisisPlayers();

        }
        return players;
    }

    /**
     * True if the situation is Extra Armies. Must call getExtraArmies(Player) to
     * know how many armies to add.
     * @return
     */
    public boolean isExtraArmiesSituation(){
        return world.getRounds().getLast().getSituation() instanceof SituationExtraArmies;
    }

    public static int getExtraArmies(Player player){
       return (player.getTotalArmies() / 2);
    }

    /**
     * Tha player returned only may add armies this round.
     * @return null if the situation is ohter than rest.
     */
    public static Player getRestPlayer(){
        Player player=null;
        if(world.getRounds().getLast().getSituation() instanceof SituationRest){
            player=((SituationRest)world.getRounds().getLast().getSituation()).getPlayer();
        }
        return player;
    }
}
